<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
	xmlns:fo="http://www.w3.org/1999/XSL/Format" 
	xmlns:hbm="urn:nhibernate-mapping-2.2"
	xmlns:msxsl="urn:schemas-microsoft-com:xslt"
	xmlns:user="urn:xslt-helper"
	xmlns:helper="urn:helper">
	<xsl:import href="property.xslt"/>
	<xsl:output method="text" encoding="UTF-8"/>
	<msxsl:script language="C#" implements-prefix="user">
		<msxsl:using namespace="System.Text.RegularExpressions" />
		<msxsl:using namespace="System.Collections.Generic" />
		<![CDATA[
    public string GetParamName(string sql, string param_num)
    {
        Regex regex = new Regex(@"\:(?<name>\w+)");
        try
        {
            MatchCollection matches = regex.Matches(sql);
            Dictionary<int, string> param = new Dictionary<int, string>();
            int n = 0;
            foreach (Match match in matches)
            {
                string val = match.Groups["name"].Value;
                if (!param.ContainsValue(val))
                    param.Add(n++, val);
            }
            int num = Convert.ToInt32(param_num);
            if (param.Count <= num)
                return "";
            else
                return param[num];
        }
        catch (Exception ex)
        {
            return ex.ToString();
        }
    }
	]]>
	</msxsl:script>

	<xsl:template match="*" priority="-1" mode="query"></xsl:template>
	<xsl:template match="*" priority="-1" mode="query-method"></xsl:template>

	<xsl:template match="hbm:resultset|hbm:sql-query" mode="query">
		<xsl:if test="count(preceding-sibling::hbm:resultset|preceding-sibling::hbm:sql-query)=0">
			<xsl:call-template name="comment">
				<xsl:with-param name="text">Враппер для хранимых запросов</xsl:with-param>
				<xsl:with-param name="level" select="1"/>
			</xsl:call-template>
			<xsl:value-of select="concat($newline, $tab, 'public partial class NamedQueries : DatabaseNamedQueries')"/>
			<xsl:value-of select="concat($newline, $tab, '{')"/>

			<xsl:apply-templates select="../*" mode="query-method"/>
			
			<xsl:value-of select="concat($newline, $tab, '}')"/>
		</xsl:if>
	</xsl:template>
	
	<xsl:template match="hbm:resultset" mode="query-method">
		<xsl:variable name="name" select="@name"/>
		<xsl:call-template name="comment">
			<xsl:with-param name="text">Типизированный результат для хранимого запроса</xsl:with-param>
			<xsl:with-param name="level" select="2"/>
		</xsl:call-template>
		<xsl:value-of select="concat($newline, $tab2, '[Serializable]')"/>
		<xsl:value-of select="concat($newline, $tab2, 'public class ', $name, ' : BaseResultSet')"/>
		<xsl:value-of select="concat($newline, $tab2, '{')"/>
		<xsl:call-template name="comment">
			<xsl:with-param name="text">Конструктор по умолчанию</xsl:with-param>
			<xsl:with-param name="level" select="3"/>
		</xsl:call-template>
		<xsl:value-of select="concat($newline, $tab3, 'public ', $name, '() {}', $newline)"/>

		<xsl:call-template name="comment">
			<xsl:with-param name="text">Инициализация строки</xsl:with-param>
			<xsl:with-param name="level" select="3"/>
		</xsl:call-template>
		<xsl:value-of select="concat($newline, $tab3, 'public override void Initialize(object resultRow)')"/>
		<xsl:value-of select="concat($newline, $tab3, '{')"/>
		
		<xsl:choose>
			<xsl:when test="count(hbm:return|hbm:return-scalar)>1">
				<xsl:value-of select="concat($newline, $tab2, $tab2, 'object [] source = (object[])resultRow;')"/>
				<xsl:for-each select="hbm:return|hbm:return-scalar">
					<xsl:choose>
						<xsl:when test="name()='return'">
							<xsl:value-of select="concat($newline, $tab2, $tab2, 'this.', @alias, ' = (', @class, ')source[', position() - 1, '];')"/>
						</xsl:when>
						<xsl:otherwise>
							<xsl:value-of select="concat($newline, $tab2, $tab2, 'this.', @column, ' = (', @type, ')source[', position() - 1, '];')"/>
						</xsl:otherwise>
					</xsl:choose>
				</xsl:for-each>
			</xsl:when>
			<xsl:otherwise>
				<xsl:for-each select="hbm:return|hbm:return-scalar">
					<xsl:choose>
						<xsl:when test="name(.)='return'">
							<xsl:value-of select="concat($newline, $tab2, $tab2, 'this.', @alias, ' = (', @class, ')resultRow;')"/>
						</xsl:when>
						<xsl:otherwise>
							<xsl:value-of select="concat($newline, $tab2, $tab2, 'this.', @column, ' = (', @type, ')resultRow;')"/>
						</xsl:otherwise>
					</xsl:choose>
				</xsl:for-each>
			</xsl:otherwise>
		</xsl:choose>
		<xsl:value-of select="concat($newline, $tab3, '}', $newline)"/>

		<xsl:for-each select="hbm:return|hbm:return-scalar">
			<xsl:call-template name="comment">
				<xsl:with-param name="text" select="concat(@alias, @column)"/>
				<xsl:with-param name="level" select="3"/>
			</xsl:call-template>
			<xsl:choose>
				<xsl:when test="name(.)='return'">
					<xsl:value-of select="concat($newline, $tab3, 'public ', @class, ' ', @alias, ';')"/>
				</xsl:when>
				<xsl:otherwise>
					<xsl:value-of select="concat($newline, $tab3, 'public ', @type, ' ', @column, ';')"/>
				</xsl:otherwise>
			</xsl:choose>
		</xsl:for-each>

		<xsl:value-of select="concat($newline, $tab2, '}')"/>
	</xsl:template>

	<xsl:template match="hbm:sql-query" mode="query-method">
		<xsl:variable name="name" select="@name"/>
		<xsl:variable name="ret-mode">
			<xsl:choose>
				<xsl:when test="count(@resultset-ref)>0">result-set</xsl:when>
				<xsl:when test="count(hbm:return)>0 and (count(hbm:return-scalar)>0 or count(hbm:return-join)>0)">list</xsl:when>
				<xsl:when test="count(hbm:return)=1 and count(hbm:return-scalar)=0">entity</xsl:when>
				<xsl:when test="count(hbm:return)=0 and count(hbm:return-scalar)=1">value</xsl:when>
			</xsl:choose>
		</xsl:variable>
		<xsl:variable name="ret-type">
			<xsl:choose>
				<xsl:when test="$ret-mode='result-set'">
					<xsl:value-of select="string('List&lt;')"/>
					<xsl:value-of select="@resultset-ref" />
					<xsl:value-of select="string('&gt;')"/>
				</xsl:when>
				<xsl:when test="$ret-mode='list'">List&lt;object[]&gt;</xsl:when>
				<xsl:when test="$ret-mode='entity'">
					<xsl:value-of select="string('List&lt;')"/>
					<xsl:call-template name="EntityType">
						<xsl:with-param name="type" select="hbm:return/@class"/>
					</xsl:call-template>
					<xsl:value-of select="string('&gt;')"/>
				</xsl:when>
				<xsl:when test="$ret-mode='value'">
					<xsl:value-of select="string('List&lt;')"/>
					<xsl:call-template name="ValueType">
						<xsl:with-param name="type" select="hbm:return-scalar/@type"/>
					</xsl:call-template>
					<xsl:value-of select="string('&gt;')"/>
				</xsl:when>
			</xsl:choose>
		</xsl:variable>

		<xsl:value-of select="$newline"/>
		<xsl:call-template name="comment">
			<xsl:with-param name="text">Получить запрос '<xsl:value-of select="$name"/>' и установить ему параметры</xsl:with-param>
			<xsl:with-param name="level" select="2"/>
		</xsl:call-template>		
		<xsl:value-of select="concat($newline, $tab2, 'public IQuery ', $name, 'Query(')"/>
		<xsl:call-template name="params_list"/>
		<xsl:value-of select="concat(')', $newline, $tab2, '{')"/>
		<xsl:value-of select="concat($newline, $tab3, 'IQuery query = session.GetNamedQuery(&quot;', $name, '&quot;);')"/>
		<xsl:call-template name="set_params_list"/>
		<xsl:value-of select="string(';')"/>
		
		<xsl:value-of select="concat($newline, $tab3, 'return query;')"/>		
		<xsl:value-of select="concat($newline, $tab2, '}')"/>

		<xsl:value-of select="$newline"/>
		<xsl:call-template name="comment">
			<xsl:with-param name="text">Выполнить запрос '<xsl:value-of select="$name"/>'</xsl:with-param>
			<xsl:with-param name="level" select="2"/>
		</xsl:call-template>
		<xsl:value-of select="concat($newline, $tab2, 'public ', $ret-type, ' ', $name, '(')"/>
		<xsl:call-template name="params_list"/>
		<xsl:value-of select="concat(')', $newline, $tab2, '{')"/>
		<xsl:value-of select="concat($newline, $tab3, $ret-type, ' result = new ', $ret-type, '();')"/>
		<xsl:value-of select="concat($newline, $tab3, 'IQuery query = ', $name, 'Query(')"/>
		<xsl:call-template name="params_list">
			<xsl:with-param name="call">true</xsl:with-param>
		</xsl:call-template>
		<xsl:value-of select="string(');')"/>

		<xsl:choose>
			<xsl:when test="$ret-mode!='result-set'">
				<xsl:value-of select="concat($newline, $tab3, 'query.List(result);')"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="concat($newline, $tab3, 'IList list = query.List();')"/>
				<xsl:value-of select="concat($newline, $tab3, 'result = ConvertToResultSet&lt;', @resultset-ref, '&gt;(list);')"/>
			</xsl:otherwise>
		</xsl:choose>
		<xsl:value-of select="concat($newline, $tab3, 'return result;')"/>
		<xsl:value-of select="concat($newline, $tab2, '}')"/>
	</xsl:template>

	<xsl:template name="params_list">
		<xsl:param name="call">false</xsl:param>
		<xsl:param name="sql" select="string(.)"/>
		<xsl:param name="num">0</xsl:param>
		<xsl:choose>
			<xsl:when test="count(hbm:query-param)>0">
				<xsl:for-each select="hbm:query-param">
					<xsl:if test="position()!='1'">
						<xsl:value-of select="string(', ')"/>
					</xsl:if>
					<xsl:variable name="type">
						<xsl:call-template name="ValueType">
							<xsl:with-param name="type" select="@type"/>
							<xsl:with-param name="not-null">true</xsl:with-param>
						</xsl:call-template>
					</xsl:variable>
					<xsl:choose>
						<xsl:when test="$call='true'">
							<xsl:value-of select="@name"/>
						</xsl:when>
						<xsl:otherwise>
							<xsl:value-of select="concat($type, ' ', @name)"/>
						</xsl:otherwise>
					</xsl:choose>
				</xsl:for-each>
			</xsl:when>
			<xsl:otherwise>
				<xsl:variable name="param-name" select="user:GetParamName($sql, $num)"/>
				<xsl:if test="string-length($param-name)>0">
					<xsl:if test="$num!='0'">
						<xsl:value-of select="string(', ')"/>
					</xsl:if>
					<xsl:if test="$call!='true'"> object </xsl:if>
					<xsl:value-of select="$param-name"/>
					<xsl:call-template name="params_list">
						<xsl:with-param name="num" select="number($num) + 1"/>
						<xsl:with-param name="sql" select="$sql"/>
						<xsl:with-param name="call" select="$call"/>
					</xsl:call-template>
				</xsl:if>
			</xsl:otherwise>
		</xsl:choose>

	</xsl:template>

	<xsl:template name="set_params_list">
		<xsl:param name="num">0</xsl:param>
		<xsl:param name="sql" select="string(.)"/>
		<xsl:choose>
			<xsl:when test="count(hbm:query-param)>0">
				<xsl:for-each select="hbm:query-param">
					<xsl:variable name="method">
						<xsl:choose>
							<xsl:when test="@type='Object'">Parameter</xsl:when>
							<xsl:otherwise>
								<xsl:value-of select="@type"/>
							</xsl:otherwise>
						</xsl:choose>
					</xsl:variable>
					<xsl:value-of select="concat($newline, $tab3, 'query')"/>
					<xsl:value-of select="concat('.Set', $method, '(&quot;')"/>
					<xsl:value-of select="concat(@name, '&quot;, ', @name, ');')"/>
				</xsl:for-each>
			</xsl:when>
			<xsl:otherwise>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
</xsl:stylesheet>
